package IO流;

import org.junit.Test;

import java.io.*;

/*
   Java IO原理
      I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输,如读/写文件,网络通讯等
      Java程序中,对于数据的输入/输出操作以"流(stream)"的方式进行
      java.io包下提供了各种"流"类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据
      输入input:读取外部数据(磁 盘、光盘等存储设备的数据)到程序(内存)中
      输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中

   流的分类
         按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
         按数据流的流向不同分为:输入流、输出流
         按流的角色的不同分为:节点流、处理流
            (抽象基类)        字节流         字符流
             输入流         InputStream     Reader
             输出流         OutputStream    Writer

   节点流和处理流
         节点流:直接从数据源或目的地读写数据
         处理流:不直接连接到数据源或目的地,而是"连接"在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能

   InputStream & Reader
          InputStream和 Reader是所有输入流的基类
          InputStream(典型实现:FileInputStream)
             int read()
             int read(byte[] b)
             int read(byte[] b,int off,int len)
         Reader(典型实现:FileReader)
              int read()
              int read(char[] c)
              int read(char[] c,int off,int len)
         程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件 IO 资源
         FileInputStream 从文件系统中的某个文件中获得输入字节,FileInputStream 用于读取非文本数据之类的原始字节流,要读取字符流,需要使用 FileReader

        InputStream
             int read()
               从输入流中读取数据的下一个字节,返回 0 到 255 范围内的 int 型字节值,如果因为已经到达流末尾而没有可用的字节,则返回值 -1
             int read(byte[] b)
               从此输入流中将最多 b.length 个字节的数据读入一个 byte数组中,如果因为已经到达流末尾而没有可用的字节,则返回值 -1,否则以整数形式返回实际读取的字节数
             int read(byte[] b,int off,int len)
               将输入流中最多 len个数据字节读入 byte数组,尝试读取 len个字节,但读取的字节也可能小于该值,以整数形式返回实际读取的字节数,如果因为流位于文件末尾而没有可用的字节,则返回值 -1
             public void close() throws IOException
               关闭此输入流并释放与该流关联的所有系统资源

        Reader
             int read()
                读取单个字符,作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码),如果已到达流的末尾,则返回 -1
             int read(char[] cbuf)
                将字符读入数组,如果已到达流的末尾,则返回 -1,否则返回本次读取的字符数
             int read(char[] cbuf,int off,int len)
                将字符读入数组的某一部分,存到数组cbuf中,从off处开始存储,最多读len个字符,如果已到达流的末尾,则返回 -1,否则返回本次读取的字符数
             public void close() throws IOException
                 关闭此输入流并释放与该流关联的所有系统资源

   OutputStream & Writer
         OutputStream和 Writer也非常相似:
             void write(int b/int c);
             void write(byte[] b/char[] cbuf);
             void write(byte[] b/char[] buff, int off, int len);
             void flush();
             void close(); 需要先刷新,再关闭此流
         因为字符流直接以字符作为操作单位,所以 Writer可以用字符串来替换字符数组,即以 String对象作为参数
             void write(String str);
             void write(String str,int off,int len);
         FileOutputStream从文件系统中的某个文件中获得输出字节,FileOutputStream用于写出非文本数据之类的原始字节流,要写出字符流,需要使用 FileWriter

      OutputStream
             void write(int b)
                将指定的字节写入此输出流,write的常规协定是:向输出流写入一个字节,要写入的字节是参数 b的八个低位,b的 24个高位将被忽略,即写入0~255范围的
             void write(byte[] b)
                将 b.length个字节从指定的 byte数组写入此输出流,write(b)的常规协定是:应该与调用 write(b, 0, b.length)的效果完全相同
             void write(byte[] b,int off,int len)
                将指定 byte数组中从偏移量 off开始的 len个字节写入此输出流
             public void flush()throws IOException
                刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标
             public void close() throws IOException
                关闭此输出流并释放与该流关联的所有系统资源

      Writer
             void write(int c)
                写入单个字符,要写入的字符包含在给定整数值的 16个低位中,16高位被忽略,即写入 0到 65535之间的Unicode码
             void write(char[] cbuf)
                写入字符数组
             void write(char[] cbuf,int off,int len)
                写入字符数组的某一部分,从off开始,写入len个字符
             void write(String str)
                写入字符串
             void write(String str,int off,int len)
                写入字符串的某一部分
             void flush()
                刷新该流的缓冲,则立即将它们写入预期目标
             public void close() throws IOException
                关闭此输出流并释放与该流关联的所有系统资源

   节点流(或文件流)的注意点
       定义文件路径时,注意:可以用"/"或者"\\"
       在写入一个文件时,如果使用构造器FileOutputStream(file),则目录下有同名文件将被覆盖
       如果使用构造器FileOutputStream(file,true),则目录下的同名文件不会被覆盖,在文件内容末尾追加内容
       在读取文件时,必须保证该文件已存在,否则报异常
       字节流操作字节,如:.mp3、.avi、.rmvb、.mp4、.jpg、.doc、.ppt
       字符流操作字符,只能操作普通文本文件,最常见的文本文件:.txt、.java、.c、.cpp等语言的源代码,尤其注意.doc、.excel、.ppt这些不是文本文件
 */
public class IO02 {

    @Test
    public void testFileReader1() {
        File file = new File("E:\\FileTest\\Hello.txt");

        Reader reader = null;
        try {
            reader = new FileReader(file);

            int data;
            while ((data = reader.read()) != -1){
                System.out.print((char)data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(reader != null){
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void testFileReader2() {
        File file = new File("E:\\FileTest\\Hello.txt");

        Reader reader = null;
        try {
            reader = new FileReader(file);

            char[] array = new char[5];
            int len;

            while ((len = reader.read(array)) != -1){ //返回每次读入到数组中字符的个数
                String str = new String(array,0,len);
                System.out.print(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void testFileWriter3(){
        File file = new File("E:\\FileTest\\Writer.txt"); //指明写出到的文件,如果文件不存在,会自动创建

        FileWriter writer = null;
        try {
            writer = new FileWriter(file,false); //是否在原有内容上追加

            writer.write("养天地正气,法古今完人\n");
            writer.write("苏州大学");

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void testCopy04(){
        File src = new File("E:\\FileTest\\Writer.txt");
        File desc = new File("E:\\FileTest\\Copy.txt");

        Reader reader = null;
        Writer writer = null;

        try {
            reader = new FileReader(src);
            writer = new FileWriter(desc);

            char[] array = new char[5];
            int len;

            while ((len = reader.read(array)) != -1){
                writer.write(array,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void testCopy05(){
        File src = new File("E:\\FileTest\\成绩合格证明.png");
        File desc = new File("E:\\FileTest\\copyImg.png");

        InputStream input = null;
        OutputStream output = null;

        try {
            input = new FileInputStream(src);
            output = new FileOutputStream(desc);

            byte[] array = new byte[1024];
            int len;

            while ((len = input.read(array)) != -1){
                output.write(array,0,len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(output != null){
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(input != null){
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
